/**
 * 
 */
package edu.pw.treegrid.server.service;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import edu.pw.treegrid.server.query.ColumnNode;
import edu.pw.treegrid.server.query.QueryTree;
import edu.pw.treegrid.server.message.Path;
import edu.pw.treegrid.server.message.Request;
import edu.pw.treegrid.server.model.DomainField;
import edu.pw.treegrid.server.model.DomainObject;
import edu.pw.treegrid.server.reportmodel.ExpressionColumn;
import edu.pw.treegrid.server.reportmodel.ReportColumn;

/** 
 * @author Piotrek
 */
public class TableRow2DomainObjectConverter {
	
    private ScriptEngine engine;
	
    public TableRow2DomainObjectConverter() {
    	ScriptEngineManager factory = new ScriptEngineManager();
        engine = factory.getEngineByName("js");
    }
    
	public List<DomainObject> convertResultSetToDomainObjects(ResultSet rs, Request request, QueryTree queryTree) throws SQLException {
		List<DomainObject> result = new LinkedList<DomainObject>();
		Columns columns = getColumns(queryTree, rs);
		ReportColumn currentReportColumn = request.getCurrentReportColumn();
		
		boolean isFolder = !request.isLeafRequest();
		int counter = 1;
		while(rs.next()) {
			DomainObject domainObject = convertRowToDomainObject(rs, columns, queryTree);
			setObjectFields(rs, currentReportColumn, request, queryTree, domainObject, counter);
			domainObject.setFolder(isFolder);
			result.add(domainObject);
			counter++;
		}
		
		return result;
	}
	
	private DomainObject convertRowToDomainObject(ResultSet rs, Columns columns, QueryTree queryTree) throws SQLException {
		DomainObject domainObject = new DomainObject();
		for(String column : columns.resultSetColumns) {
			DomainField df = new DomainField();
			df.setValue(rs.getObject(column));
			df.setDomainobject(domainObject);
			df.setReportColumn(queryTree.getReportColumnByAlias(column));
			domainObject.addDomainField(df);
		}
		for(String column : columns.otherColumns) {
			DomainField df = new DomainField();
			df.setValue("");
			df.setDomainobject(domainObject);
			df.setReportColumn(queryTree.getReportColumnByAlias(column));
			domainObject.addDomainField(df);
		}
		
		//Wyliczenie wyrazen:
		for(DomainField df : domainObject.getDomainField()) {
			engine.put(df.getReportColumn().getName(), df.getValue());
		}
		
		for(DomainField df : domainObject.getDomainField()) {
			ReportColumn reportColumn = df.getReportColumn();
			if(reportColumn instanceof ExpressionColumn) {
				ExpressionColumn ec = (ExpressionColumn)reportColumn;
				try {
					df.setValue(engine.eval(ec.getExpression()));
				} catch (ScriptException e) {
					e.printStackTrace();
				}
			}
		}
		
		return domainObject;
	}

	private void setObjectFields(ResultSet rs,
			ReportColumn currentReportColumn, Request request,
			QueryTree queryTree, DomainObject domainObject, int counter) throws SQLException {
		domainObject.setParentPath(request.getPath());
		Path path = new Path(request.getPath());
		String name = Integer.toString(counter);
		String id = Integer.toString(counter);		
		String imageSrc = "dot_icon.gif";
		if(request.isLeafRequest()) {
			currentReportColumn = request.getReport().getNameColumn();
		}
		if(currentReportColumn != null) {
			Set<ColumnNode> nodes = queryTree.getColumnNodesForReportColumn(currentReportColumn);
			for(ColumnNode cn : nodes) {
				if(nodes.size() == 1) {
					name = rs.getString(cn.getColumnAlias());
					id = rs.getString(cn.getColumnAlias());
					imageSrc = cn.getReportColumn().getImageSrc();
				}
				else if(nodes.size() == 2){
					if(cn.isIdColumn()) {
						id = rs.getString(cn.getColumnAlias());
						imageSrc = cn.getReportColumn().getImageSrc();
					}
					else {
						name = rs.getString(cn.getColumnAlias());
					}
				}
			}
		}
		if(request.isLeafRequest()) {
			// dla ostatniego poziomu id powinno byc generowane, poniewaz w przeciwnym przypadku
			// id moze nie byc unikatowe, co doprowadzi do pominiecia wyswietlenia nieunikatowych wierszy
			// przykladem jest nazwa klienta, ktora nie musi byc unikatowa
			id = Integer.toString(counter);
		}
		path.addNode(id);
		domainObject.setPath(path);
		domainObject.setName(name);
		domainObject.setImageSrc(imageSrc);
	}
	
	private Set<String> getResultSetColumnNames(ResultSet rs) throws SQLException {
		Set<String> result = new HashSet<String>();
		ResultSetMetaData rsmd = rs.getMetaData();
		for(int i=1;i<=rsmd.getColumnCount();++i) {
			result.add(rsmd.getColumnName(i));
		}
		return result;
	}
	
	private static class Columns {
		List<String> resultSetColumns = new LinkedList<String>();
		List<String> otherColumns = new LinkedList<String>();
	}
	
	private Columns getColumns(QueryTree queryTree, ResultSet rs) throws SQLException {
		Columns columns = new Columns();
		Set<String> resultSetColumnNames = getResultSetColumnNames(rs);
		List<ColumnNode> reportColumns = queryTree.getNotIdColumnNodes();
		for(ColumnNode c: reportColumns) {
			String alias = c.getColumnAlias();
			if(resultSetColumnNames.contains(alias)) {
				columns.resultSetColumns.add(alias);
			}
			else {
				columns.otherColumns.add(alias);
			}
		}
		return columns;
	}
}